package com.bjb.vr.monitor.config;

import cn.hutool.core.util.IdUtil;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.bjb.vr.common.utils.ZkClientUtil;
import com.bjb.vr.monitor.ao.StatusAlarmAo;
import com.bjb.vr.monitor.constant.AlarmConstant;
import com.bjb.vr.monitor.constant.ServiceConstant;
import com.bjb.vr.monitor.properties.AlarmProperties;
import com.bjb.vr.monitor.properties.EmailProperties;
import com.bjb.vr.monitor.properties.VersionProperties;
import com.bjb.vr.monitor.util.EmailUtil;
import com.bjb.vr.monitor.util.ServiceStatusSender;
import com.google.common.base.Splitter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.utils.ZKPaths;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @description: 读取自定义配置文件信息
 * @author: HuJingBo
 * @time: 2022/2/21 09:14
 */
@Order(1)
@Slf4j
@Component
@ConditionalOnProperty(value = "zookeeper.monitor.enable", matchIfMissing = false)
public class InitStarter implements CommandLineRunner {

    @Resource
    private NacosDiscoveryProperties discoveryProperties;

    @Resource
    private Environment environment;

    @Resource
    VersionProperties versionProp;

    @Resource
    private CuratorFramework zkClient;

    @Resource
    private EmailUtil emailUtil;

    @Resource
    AlarmProperties alarmProperties;

    @Resource
    EmailProperties emailProperties;

//    @Resource
//    private Map<String, String> arthasConfigMap;


    /**
     * 只能监听monitor自己上线状态，下线状态没办法监听
     */
    public void init() {
        String ip = discoveryProperties.getIp();
        String port = environment.getProperty("server.port");
//        String agentId = arthasConfigMap.get("agent-id");
        String agentId = IdUtil.objectId();
        String serviceName = discoveryProperties.getService();
        String info = String.format("%s;%s;%s;%s", serviceName, ip, port, agentId);
        String path = "/servers/" + serviceName + "/" + serviceName + ";" + ip + ";" + port + ";" + agentId;
        ZkClientUtil.createTempNode(zkClient, path, info);
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("项目启动信息 ......");
        log.info("当前Git版本号(commitId):{}", versionProp.getGit());
        log.info("当前Jenkins版本号(buildId):{}", versionProp.getJenkins());
        log.info("当前项目版本号(imageTag):{}", versionProp.getProject());
        // 开始监听服务状态
        childEvent(zkClient, alarmProperties, emailProperties, emailUtil);
        // 注册自己
        init();
    }

    /**
     * zookeeper监控相关
     *
     * @param client
     * @param alarmProperties
     * @param emailProperties
     * @param emailUtil
     * @throws Exception
     */
    private static void childEvent(CuratorFramework client, AlarmProperties alarmProperties, EmailProperties emailProperties, EmailUtil emailUtil) throws Exception {
        // 创建监听器节点
        TreeCache cache = new TreeCache(client, "/servers");
        cache.start();

        // 注册监听器
        cache.getListenable().addListener(new TreeCacheListener() {

            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                if (event.getType().equals(TreeCacheEvent.Type.NODE_ADDED)) {
                    String nodePath = event.getData().getPath();
                    String parentPath = ZKPaths.getPathAndNode(nodePath).getPath();
                    List<String> children = client.getChildren().forPath(parentPath);
                    try {
                        String childInfo = new String(client.getData().forPath(nodePath));
                        long ctime = event.getData().getStat().getCtime();
                        log.info("监听到新增节点>>> 节点路径:{}|节点信息：{}", nodePath, childInfo);
                        String status = "UP";
                        sendAlarmMessage(alarmProperties, emailUtil, emailProperties, AlarmConstant.STATUS_UP, status, childInfo, ctime, children.size());
                    } catch (Exception e) {
                        log.error("发送上线报警消息失败>>> {}", e);
                    }
                } else if (event.getType().equals(TreeCacheEvent.Type.NODE_REMOVED)) {
                    String nodePath = event.getData().getPath();
                    String parentPath = ZKPaths.getPathAndNode(nodePath).getPath();
                    List<String> children = client.getChildren().forPath(parentPath);
                    try {
                        String childInfo = ZKPaths.getNodeFromPath(nodePath);
                        long ctime = System.currentTimeMillis();
                        log.info("监听到删除节点>>> 节点路径:{}|节点信息：{}", nodePath, childInfo);
                        String status = "DOWN";
                        sendAlarmMessage(alarmProperties, emailUtil, emailProperties, AlarmConstant.STATUS_DOWN, status, childInfo, ctime, children.size());
                    } catch (Exception e) {
                        log.error("发送下线报警消息失败>>> {}", e);
                    }
                }
            }
        });
    }

    /**
     * 发送报警消息
     *
     * @param alarmProperties
     * @param emailUtil
     * @param emailProperties
     * @param title
     * @param status
     * @param nodeInfo
     * @param ctime
     * @param size
     */
    private static void sendAlarmMessage(AlarmProperties alarmProperties, EmailUtil emailUtil, EmailProperties emailProperties, String title, String status, String nodeInfo, Long ctime, Integer size) {
        if (StringUtils.isBlank(nodeInfo)) {
            return;
        }

        List<String> toList = Splitter.on(";").trimResults().splitToList(nodeInfo);
        StatusAlarmAo alarmAo = new StatusAlarmAo();
        alarmAo.setServiceName(toList.get(0));
        alarmAo.setServiceIP(toList.get(1));
        alarmAo.setServicePort(toList.get(2));
        alarmAo.setServiceAgentId(toList.get(3));
        alarmAo.setServiceStatus(status);
        alarmAo.setStartTime(ctime);
        alarmAo.setInstanceSum(size);

        if (alarmProperties.getType().equals(ServiceConstant.SEND_DINGDING)) {
            // 钉钉消息
            ServiceStatusSender.sendDingDingMsg(alarmAo, title);
        } else if (alarmProperties.getType().equals(ServiceConstant.SEND_MAIL)) {
            // 邮件消息
            ServiceStatusSender.sendEmailMsg(alarmAo, emailUtil, emailProperties.getReceivers(), title);
        } else if (alarmProperties.getType().equals(ServiceConstant.SEND_ALL)) {
            // 钉钉消息 + 邮件消息
            ServiceStatusSender.sendDingDingMsg(alarmAo, title);
            ServiceStatusSender.sendEmailMsg(alarmAo, emailUtil, emailProperties.getReceivers(), title);
        }
        return;
    }
}
